﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Windows.Forms;
using DevExpress.XtraEditors.DXErrorProvider;
using Loki.Commands;

namespace Loki.UI.Win
{
    public class FormBase : ViewBase
    {
        protected DevExpress.XtraLayout.LayoutControl LAY_Root;
        private WaitControl CTR_Wait;
        protected DevExpress.XtraLayout.LayoutControlGroup LAG_Root;

        public FormBase()
        {
            InitializeComponent();
            BindingChanged += new EventHandler(MDIFormBase_BindingChanged);
        }

        void MDIFormBase_BindingChanged(object sender, EventArgs e)
        {
            this.WatchChange(ViewModel, v => v.Status, c => c.ViewModel_StatusChanged);

            HandleValidation(ViewModel.Validate, Validators.ToArray());
        }

        void ViewModel_StatusChanged(object sender, PropertyChangedEventArgs e)
        {
            if (ViewModel != null)
            {
                Action L_Actor = delegate()
                {
                    if (CTR_Wait == null)
                    {
                        CTR_Wait = new WaitControl();
                        // 
                        // CTR_Wait
                        // 
                        this.CTR_Wait.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
                        this.CTR_Wait.Location = new System.Drawing.Point(109, 12);
                        this.CTR_Wait.Name = "CTR_Wait";
                        this.CTR_Wait.Padding = new System.Windows.Forms.Padding(10);
                        this.CTR_Wait.Size = new System.Drawing.Size(430, 80);
                        this.CTR_Wait.TabIndex = 4;
                        this.CTR_Wait.Visible = false;
                        this.Controls.Add(CTR_Wait);
                        this.Controls.SetChildIndex(CTR_Wait, 0);
                    }
                    if (!string.IsNullOrWhiteSpace(ViewModel.Status))
                    {
                        CTR_Wait.Parent = this;
                        CTR_Wait.Height = 80;
                        CTR_Wait.LBL_Text.Text = ViewModel.Status;
                        CTR_Wait.Left = LAY_Root.Left + (LAY_Root.Width - CTR_Wait.Width) / 2;
                        CTR_Wait.Top = LAY_Root.Top + (LAY_Root.Height - CTR_Wait.Height) / 2;
                        Log.Debug("Left:" + CTR_Wait.Left + " Top:" + CTR_Wait.Top);
                        LAY_Root.Enabled = false;
                        CTR_Wait.Show();
                    }
                    else
                    {
                        LAY_Root.Enabled = true;
                        CTR_Wait.Hide();
                    }
                };
                if (!IsDisposed && IsHandleCreated)
                {
                    if (InvokeRequired)
                        BeginInvoke(L_Actor);
                    else
                        L_Actor();
                }
            }
        }

        private void InitializeComponent()
        {
            this.LAY_Root = new DevExpress.XtraLayout.LayoutControl();
            this.LAG_Root = new DevExpress.XtraLayout.LayoutControlGroup();
            ((System.ComponentModel.ISupportInitialize)(this.BMA_Main)).BeginInit();
            ((System.ComponentModel.ISupportInitialize)(this.LAY_Root)).BeginInit();
            ((System.ComponentModel.ISupportInitialize)(this.LAG_Root)).BeginInit();
            this.SuspendLayout();
            // 
            // LAY_Root
            // 
            this.LAY_Root.AllowCustomizationMenu = false;
            this.LAY_Root.Dock = System.Windows.Forms.DockStyle.Fill;
            this.LAY_Root.Location = new System.Drawing.Point(0, 0);
            this.LAY_Root.Name = "LAY_Root";
            this.LAY_Root.Root = this.LAG_Root;
            this.LAY_Root.Size = new System.Drawing.Size(282, 255);
            this.LAY_Root.TabIndex = 0;
            this.LAY_Root.Text = "Root layout";
            this.LAY_Root.ToolTipController = this.TOO_Controller;
            // 
            // LAG_Root
            // 
            this.LAG_Root.CustomizationFormText = "Root";
            this.LAG_Root.EnableIndentsWithoutBorders = DevExpress.Utils.DefaultBoolean.True;
            this.LAG_Root.GroupBordersVisible = false;
            this.LAG_Root.Location = new System.Drawing.Point(0, 0);
            this.LAG_Root.Name = "LAG_Root";
            this.LAG_Root.Padding = new DevExpress.XtraLayout.Utils.Padding(0, 0, 0, 0);
            this.LAG_Root.Size = new System.Drawing.Size(282, 255);
            this.LAG_Root.Text = "Root";
            this.LAG_Root.TextVisible = false;
            // 
            // FormBase
            // 
            this.ClientSize = new System.Drawing.Size(282, 255);
            this.Controls.Add(this.LAY_Root);
            this.Name = "FormBase";
            this.Controls.SetChildIndex(this.LAY_Root, 0);
            ((System.ComponentModel.ISupportInitialize)(this.BMA_Main)).EndInit();
            ((System.ComponentModel.ISupportInitialize)(this.LAY_Root)).EndInit();
            ((System.ComponentModel.ISupportInitialize)(this.LAG_Root)).EndInit();
            this.ResumeLayout(false);

        }

        protected override void OnFormClosing(FormClosingEventArgs e)
        {
            if (e.CloseReason == CloseReason.UserClosing && ViewModel.IsDirty)
            {
                bool L_CloseConfirm = MessageBoxes.Confirm(Messages.UIMessages.CONFIRM_CLOSE);
                e.Cancel = !L_CloseConfirm;
                if (L_CloseConfirm)
                    ViewModel.AcceptChanges();
            }

            base.OnFormClosing(e);
        }

        #region Validation
        protected virtual IEnumerable<DXValidationProvider> Validators
        {
            get { return new List<DXValidationProvider>(); }
        }

        protected void IfValid(ICommand P_Command, params DXValidationProvider[] P_Validators)
        {
            IfValid(() => P_Command.Execute(null), P_Validators);
        }

        protected void IfValid(Action P_IfValidMethod, params DXValidationProvider[] P_Validators)
        {
            IEnumerable<ValidationMessage> L_Errors = ValidateData(false, P_Validators);
            if (!L_Errors.Any())
                P_IfValidMethod();
            else
                ErrorSummary.DisplayErrorSummary(L_Errors.ToArray());
        }

        protected virtual IEnumerable<ValidationMessage> ValidateData(bool L_UseWarnings = false, params DXValidationProvider[] P_Validators)
        {
            List<ValidationMessage> L_Return = new List<ValidationMessage>();
            IEnumerable<DXValidationProvider> L_ValidatorList = P_Validators;
            if (L_ValidatorList == null)
                L_ValidatorList = Validators;
            foreach (DXValidationProvider L_Validator in L_ValidatorList)
            {
                if (!L_Validator.Validate())
                {
                    foreach (Control L_Control in L_Validator.GetInvalidControls())
                    {
                        ValidationRuleBase L_Rule = L_Validator.GetValidationRule(L_Control);
                        if (L_UseWarnings)
                            L_Rule.ErrorType = ErrorType.Warning;
                        else
                            L_Rule.ErrorType = ErrorType.Default;
                        L_Validator.Validate();

                        L_Return.Add(new ValidationMessage() { Message = L_Rule.ErrorText, Type = L_Rule.ErrorType });
                    }
                }
            }
            return L_Return;
        }

        protected void ExecuteOnClick(Control P_Button, Action P_Command, params DXValidationProvider[] P_Validators)
        {
            P_Button.Click += delegate(object P_Sender, EventArgs e)
            {
                IfValid(P_Command, P_Validators);
            };

            foreach (var item in P_Validators)
            {
                DataBinder.AddValidator(item);
            }
        }

        protected void ExecuteOnClick(Control P_Button, ICommand P_Command, params DXValidationProvider[] P_Validators)
        {
            P_Button.Click += delegate(object P_Sender, EventArgs e)
            {
                IfValid(P_Command, P_Validators);
            };

            foreach (var item in P_Validators)
            {
                DataBinder.AddValidator(item);
            }
        }

        private void HandleValidation(ICommand P_Command, params DXValidationProvider[] P_Validators)
        {
            Commands.Handle(P_Command, (s, e) => { e.CanExecute |= ViewModel != null && ViewModel.ValidationEnabled; }, (s, e) =>
            {
                ValidationMode L_Mode = e.Parameter == null ? ValidationMode.None : (ValidationMode)e.Parameter;
                if (ViewModel != null)
                {
                    DataBinder.ResetBindings();
                    UIContext.ProtectUIDispatcher((state) => Validate(L_Mode, P_Validators));
                }
            });
            foreach (var item in P_Validators)
            {
                DataBinder.AddValidator(item);
            }

        }
        protected virtual void Validate(ValidationMode P_Mode, params DXValidationProvider[] P_Validators)
        {
            bool L_UseWarnings = P_Mode == ValidationMode.SilentWarning || P_Mode == ValidationMode.Warning;
            bool L_Silent = P_Mode == ValidationMode.SilentError || P_Mode == ValidationMode.SilentWarning;
            if (P_Mode != ValidationMode.None)
            {
                IEnumerable<ValidationMessage> L_Messages = ValidateData(L_UseWarnings, P_Validators);
                if (!L_Silent && L_Messages.Any())
                {
                    InputErrorMessageBox.DisplayErrorSummary(L_Messages.ToArray());
                }

                if (ViewModel != null)
                {
                    ViewModel.IsValid &= !L_Messages.Any();
                }
            }
            else
            {
                foreach (DXValidationProvider L_Validator in P_Validators)
                {
                    foreach (Control L_Control in L_Validator.GetInvalidControls())
                    {
                        L_Validator.RemoveControlError(L_Control);
                    }
                }
            }
        }
        #endregion
    }
}
